package com.msb.juc.c_018_Atomic;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * 解决同样的问题，更高效的方法：使用 AtomicXxx类
 * AtomicXxx类本身方法都是原子性的，但不能保证多个方法连续调用是原子性的
 * 凡是 AtomicXxx的类，内部都是使用 Unsafe类中的 CAS实现的
 */
public class T01_AtomicInteger {
//    /*volatile*/ int count = 0;

    /*
    CompareAndSet
    cas(V, Expected, NewValue) {
        if(V == E)
            V = New
        else
            try again or fail
    }

    CPU原语支持，CAS在执行时不会被打断

    ABA问题
        使用版本号解决
        线程1 想把A变成B
        线程2 把B变成了A
            这时可以把第一个A编号为1.0，B编号为2.0，第二个A编号为3.0

        如果 A，B是简单类型，问题不大
        但是如果是引用类型，就会出问题

        比喻：
            你的女朋友和你分手了，
            你的女朋友找了好几个新男朋友，
            你的女朋友来找你复合，
            此时她已经不是当初那个她了！



        Unsafe
            直接操作内存：allocateMemory putXx freeMemory pageSize
            直接生成类实例：allocateInstance
            直接操作类或实例变量：objectFieldOffset, getInt, getObject
            CAS相关操作：weakCompareAndSetObject Int Long

     */

    AtomicInteger count = new AtomicInteger(0);

    /*synchronized*/ void m() {
        for (int i = 0; i < 10000; i++) {
            // count++;
            count.incrementAndGet();
        }
    }

    public static void main(String[] args) {
        T01_AtomicInteger t = new T01_AtomicInteger();

        List<Thread> threads = new ArrayList<>();

        for (int i = 0; i < 10; i++) {
            threads.add(new Thread(t::m, "thread-" + i));
        }

        threads.forEach((o) -> o.start());

        threads.forEach((o) -> {
            try {
                o.join();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });
    }
}
